﻿using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;

namespace Maikebing.Data.Taos
{
    public static class DataReaderExtensions
    {
        public static T ToJson<T>(this IDataReader dataReader) where T : class
        {
            return dataReader.ToJson().ToObject<T>();
        }
        public static List<T> ToList<T>(this IDataReader dataReader) where T : class
        {
            return dataReader.ToJson().ToObject<List<T>>();
        }
        public static List<T> ToObject<T>(this IDataReader dataReader)
        {
            List<T> jArray = new List<T>();
            try
            {
                var t = typeof(T);
                var pots = t.GetProperties();
                //获取JsonPropertyAttribute映射
                var fieldMap = new Dictionary<string, string>();
                var isCustomField = false;
                foreach (var property in pots)
                {
                    isCustomField = false;
                    foreach (var attr in System.Attribute.GetCustomAttributes(property))
                    {
                        if (attr is JsonPropertyAttribute)
                        {
                            var a = (JsonPropertyAttribute)attr;
                            fieldMap.Add(property.Name, a.PropertyName);
                            isCustomField = true;
                            break;
                        }
                    }

                    if (isCustomField == false)
                    {
                        fieldMap.Add(property.Name, property.Name.ToLower());
                    }
                }

                while (dataReader.Read())
                {
                    T jObject = Activator.CreateInstance<T>();
                    for (int i = 0; i < dataReader.FieldCount; i++)
                    {
                        try
                        {
                            string strKey = dataReader.GetName(i);
                            if (dataReader[i] != DBNull.Value)
                            {
                                var pr = from p in pots
                                         where (GetOrDefault(fieldMap, p.Name, p.Name) == strKey || p.Name == strKey) && p.CanWrite
                                         select p;
                                if (pr.Any())
                                {
                                    var pi = pr.FirstOrDefault();
                                    pi.SetValue(jObject, ChangeType(dataReader[i], pi.PropertyType));
                                }
                            }
                        }
                        catch (Exception)
                        {

                        }
                    }
                    jArray.Add(jObject);
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.Message);
            }
            return jArray;
        }

        public static JArray ToJson(this IDataReader dataReader)
        {
            JArray jArray = new JArray();
            try
            {

                while (dataReader.Read())
                {
                    JObject jObject = new JObject();
                    for (int i = 0; i < dataReader.FieldCount; i++)
                    {
                        try
                        {
                            string strKey = dataReader.GetName(i);
                            if (dataReader[i] != DBNull.Value)
                            {
                                object obj = Convert.ChangeType(dataReader[i], dataReader.GetFieldType(i));
                                jObject.Add(strKey, JToken.FromObject(obj));
                            }
                        }
                        catch (Exception)
                        {

                        }
                    }
                    jArray.Add(jObject);
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.Message);
            }
            return jArray;
        }
        public static DataTable ToDataTable(this IDataReader reader)
        {
            var datatable = new DataTable();
            datatable.Load(reader);
            return datatable;
        }


        public static object ChangeType(object value, Type conversion)
        {
            var t = conversion;

            if (t.IsGenericType && t.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
            {
                if (value == null)
                {
                    return null;
                }

                t = Nullable.GetUnderlyingType(t);
            }

            // 判断 t 是否为 decimal 类型
            if (t == typeof(decimal))
            {
                if (value is float floatValue)
                {
                    var result = Convert.ToDecimal(floatValue); //防止先转换成Double导致小数位增多
                    if (result != (decimal)floatValue)
                    {
                        return Convert.ToDecimal(Convert.ToDouble(floatValue)); //先转换成double再转换成decimal防止精度丢失 eg：1744881.5f变成1744882
                    }
                    return result;
                }
                return Convert.ToDecimal(value);  //不使用Convert.ChangeType转换为 decimal，避免四舍五入
            }

            return Convert.ChangeType(value, t);
        }

        /// <summary>
        /// 获取字典中的指定键的值，如果指定的键不存在，则返回 <paramref name="defaultValue"/> 。
        /// </summary>
        public static TValue GetOrDefault<TKey, TValue>(IDictionary<TKey, TValue> instance, TKey key, TValue defaultValue = default(TValue))
        {
            return !instance.TryGetValue(key, out var result) ? defaultValue : result;
        }
    }
}
